/* *****************************************************************************
 * JFab (http://code.google.com/p/jfab)
 * Copyright (c) 2011 JFab.org
 * Admin jfab@jeffreythompson.net
 *
 * See the file "LICENSE.txt" for information on usage and redistribution of
 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
 * *****************************************************************************/

package org.jfab.core.analyzer;

import java.lang.reflect.Modifier;
import java.util.Comparator;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.Validate;
import org.jfab.core.collection.CGAnnotationList;
import org.jfab.core.collection.CGFieldList;
import org.jfab.core.collection.CGMethodDeclarationList;
import org.jfab.core.collection.CGTypeList;
import org.jfab.core.collection.CommentList;
import org.jfab.core.collection.ImportMap;
import org.jfab.core.collection.ModifierList;
import org.jfab.core.factory.CGAnnotationFactory;
import org.jfab.core.factory.CGInterfaceFactory;
import org.jfab.core.factory.CGTypeFactory;
import org.jfab.core.factory.StringFactory;
import org.jfab.core.model.CGInterface;
import org.jfab.core.model.CGType;
import org.jfab.core.model.CGTypeUtilities;
import org.jfab.core.model.TypeFactory;

/**
 * Provides a interface analyzer.
 */
public final class InterfaceAnalyzer extends
        AbstractCompilationUnitAnalyzer<CGInterface, Class<?>>
{
    /** Field analyzer. */
    private final FieldAnalyzer _fieldAnalyzer;

    /** Interface factory. */
    private final CGInterfaceFactory _interfaceFactory;

    /** Interface method analyzer. */
    private final InterfaceMethodAnalyzer _interfaceMethodAnalyzer;

    /**
     * Construct this object with the given parameters.
     * 
     * @param typeFactory Type factory.
     * @param cgTypeUtils Code generator type utilities. (required)
     * @param cgTypeFactory Code generator type factory.
     * @param stringFactory String factory.
     * @param annotationFactory Annotation factory.
     * @param comparator Comparator.
     * @param interfaceFactory Interface factory.
     * @param fieldAnalyzer Field analyzer.
     * @param interfaceMethodAnalyzer Interface method analyzer.
     */
    public InterfaceAnalyzer(final TypeFactory typeFactory,
            final CGTypeUtilities cgTypeUtils,
            final CGTypeFactory cgTypeFactory,
            final StringFactory stringFactory,
            final CGAnnotationFactory annotationFactory,
            final Comparator<CGInterface> comparator,
            final CGInterfaceFactory interfaceFactory,
            final FieldAnalyzer fieldAnalyzer,
            final InterfaceMethodAnalyzer interfaceMethodAnalyzer)
    {
        super(typeFactory, cgTypeUtils, cgTypeFactory, stringFactory,
                annotationFactory, comparator);

        _interfaceFactory = interfaceFactory;
        _fieldAnalyzer = fieldAnalyzer;
        _interfaceMethodAnalyzer = interfaceMethodAnalyzer;
    }

    @Override
    public final CGInterface analyze(final Class<?> aClass,
            final String javaSource)
    {
        Validate.notNull(aClass, "aClass is null");

        CGInterface answer = null;

        final CGTypeList referencedTypes = null;
        String packageName = null;
        if (aClass.getPackage() != null)
        {
            packageName = aClass.getPackage().getName();
        }
        final CommentList commentLines = parseCommentLines(javaSource);
        final CGAnnotationList annotations = null;
        final ModifierList modifiers = filterModifiers(aClass.getModifiers());
        final String shortClassName = aClass.getSimpleName();
        final List<String> typeParameters = null;
        final CGTypeList extendsTypes = parseExtendsTypes(packageName,
                aClass.getInterfaces(), javaSource);
        final CGFieldList fields = new CGFieldList(getFieldAnalyzer().analyze(
                aClass.getDeclaredFields(), javaSource));
        final CGMethodDeclarationList methods = new CGMethodDeclarationList(
                getInterfaceMethodAnalyzer().analyze(
                        aClass.getDeclaredMethods(), javaSource));

        answer = getInterfaceFactory().createInterface(referencedTypes,
                packageName, commentLines, annotations, modifiers,
                shortClassName, typeParameters, extendsTypes, fields, methods);
        answer.setJavaType(getCgTypeFactory().createType(aClass));

        return answer;
    }

    /**
     * @param modifiers Modifiers.
     * 
     * @return the given parameter filtered for particular modifiers.
     */
    private ModifierList filterModifiers(final int modifiers)
    {
        int value = modifiers;

        if (Modifier.isAbstract(value))
        {
            value -= Modifier.ABSTRACT;
        }

        return new ModifierList(value);
    }

    /**
     * @return the fieldAnalyzer
     */
    private FieldAnalyzer getFieldAnalyzer()
    {
        return _fieldAnalyzer;
    }

    /**
     * @return the interfaceFactory
     */
    private CGInterfaceFactory getInterfaceFactory()
    {
        return _interfaceFactory;
    }

    /**
     * @return the interfaceMethodAnalyzer
     */
    private InterfaceMethodAnalyzer getInterfaceMethodAnalyzer()
    {
        return _interfaceMethodAnalyzer;
    }

    /**
     * @param packageName Package name.
     * @param extendsClasses Extends classes.
     * @param sourceCode Source code.
     * 
     * @return implements types parsed from the given parameters.
     */
    private CGTypeList parseExtendsTypes(final String packageName,
            final Class<?>[] extendsClasses, final String sourceCode)
    {
        CGTypeList answer = null;

        if ((extendsClasses != null) && (extendsClasses.length > 0))
        {
            answer = new CGTypeList();

            final ImportMap importMap = analyzeImports(sourceCode);
            final int size = extendsClasses.length;
            final String text = StringUtils.substringBetween(sourceCode,
                    "extends", "{");

            if (StringUtils.isNotEmpty(text))
            {
                final String[] texts = text.split(",");
                final CGTypeFactory cgTypeFactory = getCgTypeFactory();

                for (int i = 0; i < size; i++)
                {
                    final CGType cgType = cgTypeFactory.createType(packageName,
                            importMap, texts[i]);
                    answer.add(cgType);
                }
            }
        }

        return answer;
    }
}
